#pragma once

#include "RoomDefines.h"
#include "RoomMessage.h"
#include "SocketServer.h"

namespace RoomFW {

class PortRouter;

//
// Class:	PortRouterMessage
//
// Description:	TODO
//
// Author:	Andrew Sage
//
class PortRouterMessage
{
public:
	// Message ids for router-to-router messages.
	enum RouterMessageId
	{
		RMID_CONNECT,
		RMID_REGISTER,
		RMID_UNREGISTER,
		RMID_BIND,
		RMID_BIND_ACK,
		RMID_UNBIND,
		RMID_SEND,
		RMID_NO_REPLY
	};

	typedef ::boost::shared_ptr<PortRouterMessage> Ptr;

	static PortRouterMessage::Ptr Create(const std::string& msgStr);

	virtual RouterMessageId getId() const = 0;

	virtual void serialize(oarchive& /*ar*/, const unsigned int /*version*/) const = 0;
	virtual void serialize(iarchive& /*ar*/, const unsigned int /*version*/) = 0;

	virtual void dispatch(PortRouter* router) = 0;

// protected:

};

const char* toString(PortRouterMessage::RouterMessageId rmid);

class PRM_Connect : public PortRouterMessage
{
public:
	virtual RouterMessageId getId() const;
	virtual void serialize(oarchive& /*ar*/, const unsigned int /*version*/) const;
	virtual void serialize(iarchive& /*ar*/, const unsigned int /*version*/);
	virtual void dispatch(PortRouter* router);

	PRM_Connect();
	PRM_Connect(
		int port,
		std::string address);
	int port();
	std::string address();

private:
	int port_;
	std::string address_;
};


class PRM_Register : public PortRouterMessage
{
public:
	virtual RouterMessageId getId() const;
	virtual void serialize(oarchive& /*ar*/, const unsigned int /*version*/) const;
	virtual void serialize(iarchive& /*ar*/, const unsigned int /*version*/);
	virtual void dispatch(PortRouter* router);

	PRM_Register();
	PRM_Register(const std::string& portName, ContractTypeId typeId, bool isConjugate);
	std::string portName() const;
	ContractTypeId typeId() const;
	bool isConjugate() const;

private:
	std::string portName_;
	ContractTypeId typeId_;
	bool isConjugate_;
};

class PRM_Unregister : public PortRouterMessage
{
public:
	virtual RouterMessageId getId() const;
	virtual void serialize(oarchive& /*ar*/, const unsigned int /*version*/) const;
	virtual void serialize(iarchive& /*ar*/, const unsigned int /*version*/);
	virtual void dispatch(PortRouter* router);
};

class PRM_Bind : public PortRouterMessage
{
public:
	virtual RouterMessageId getId() const;
	virtual void serialize(oarchive& /*ar*/, const unsigned int /*version*/) const;
	virtual void serialize(iarchive& /*ar*/, const unsigned int /*version*/);
	virtual void dispatch(PortRouter* router);

	PRM_Bind();
	PRM_Bind(const std::string& portName, PortIndex portIndex);
	std::string portName() const;
	PortIndex portIndex() const;

private:
	std::string portName_;
	PortIndex portIndex_;
};

class PRM_Bind_Ack : public PortRouterMessage
{
public:
	virtual RouterMessageId getId() const;
	virtual void serialize(oarchive& /*ar*/, const unsigned int /*version*/) const;
	virtual void serialize(iarchive& /*ar*/, const unsigned int /*version*/);
	virtual void dispatch(PortRouter* router);


	PRM_Bind_Ack();
	PRM_Bind_Ack(PortIndex portIndex);
	PortIndex portIndex() const;

private:
	PortIndex portIndex_;
};

class PRM_Unbind : public PortRouterMessage
{
public:
	virtual RouterMessageId getId() const;
	virtual void serialize(oarchive& /*ar*/, const unsigned int /*version*/) const;
	virtual void serialize(iarchive& /*ar*/, const unsigned int /*version*/);
	virtual void dispatch(PortRouter* router);
};

class PRM_Send : public PortRouterMessage
{
public:
	virtual RouterMessageId getId() const;
	virtual void serialize(oarchive& /*ar*/, const unsigned int /*version*/) const;
	virtual void serialize(iarchive& /*ar*/, const unsigned int /*version*/);
	virtual void dispatch(PortRouter* router);

	PRM_Send();
	PRM_Send(
		ContractTypeId contractId,
		PortIndex portIndex,
		MessageID messageId,
		IPayloadSP payload,
		std::string senderName,
		int replyId);
	ContractTypeId contractId() const;
	PortIndex portIndex() const;
	MessageID messageId() const;
	IPayloadSP payload() const;
	IPayloadSP releasePayload();
	std::string senderName();
	int replyId() const;

private:
	ContractTypeId contractId_;
	PortIndex portIndex_;
	MessageID messageId_;
	IPayloadSP payload_;
	std::string senderName_;
	int replyId_;
};

class PRM_NoReply : public PortRouterMessage
{
public:
	virtual RouterMessageId getId() const;
	virtual void serialize(oarchive& /*ar*/, const unsigned int /*version*/) const;
	virtual void serialize(iarchive& /*ar*/, const unsigned int /*version*/);
	virtual void dispatch(PortRouter* router);

	PRM_NoReply();
	PRM_NoReply(int replyId);
	int replyId() const;

private:
	int replyId_;
};

}
